#include "stdafx.h"

#include "MonkeyScene.h"
#include <HSModel/SharedConstants.h>
MonkeyScene::MonkeyScene(OgreFramework& i_ogre_framework, std::shared_ptr<Ogre::OverlaySystem> i_overlay)
  : m_ogre_framework(i_ogre_framework)
  , mp_overlay(i_overlay)
  , mp_camera(nullptr)
  {
  _CreateScene();
  }

MonkeyScene::~MonkeyScene()
  {

  }



void MonkeyScene::_CreateScene()
  {
  Ogre::SceneManager* p_scene_manager = m_ogre_framework.CreateSceneManager(Ogre::ST_GENERIC, "MonkeySceneManager");
  p_scene_manager->setAmbientLight(Ogre::ColourValue(0.0, 0.0, 0.0));

  // Add this to every scene manager
  p_scene_manager->addRenderQueueListener(mp_overlay.get());

  Ogre::Camera* p_camera = m_ogre_framework.CreateCamera("MonkeyCamera");
  p_camera->setPosition(Ogre::Vector3(0, 160, 80));
  p_camera->lookAt(Ogre::Vector3(40, -40, 40));
  p_camera->setNearClipDistance(5);
 
  mp_camera.reset(new GeneralCamera(p_camera));
  m_ogre_framework.GetViewport()->setCamera(p_camera);
  Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

  _LoadTerrain();
  }

bool MonkeyScene::KeyPressed(const OIS::KeyEvent &keyEventRef)
  {
  mp_camera->InjectKeyDown(keyEventRef);
  return true;
  }

bool MonkeyScene::KeyReleased(const OIS::KeyEvent &keyEventRef) 
  {
  mp_camera->InjectKeyUp(keyEventRef);
  return true;
  }

bool MonkeyScene::MouseMoved(const OIS::MouseEvent &evt) 
  {
  return true;
  }

bool MonkeyScene::MousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id) 
  {
  return true;
  }

bool MonkeyScene::MouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id) 
  {
  return true;
  }

void MonkeyScene::_LoadTerrain()
  {
  // add static geometry here
  
  // 1) create huge plane with grass texture
  Ogre::Plane plane;
  plane.normal = Ogre::Vector3::UNIT_Y;
  plane.d = 0;

  const double ground_size = GroundConstants::CELL_COUNT * GroundConstants::CELL_SIZE;
  const double plane_size = ground_size + 25000.0;
  
  Ogre::SceneManager* p_scene_manager = m_ogre_framework.GetSceneManager("MonkeySceneManager");

  // create 4 planes which surround ground
  const size_t plane_count = 4;
  std::vector<Ogre::Entity*> plane_entities(plane_count);
  std::vector<Ogre::SceneNode*>   plane_nodes(plane_count);
  for (size_t i = 0; i < plane_count; ++i)
    {
    if (i % 2 == 0)
      Ogre::MeshManager::getSingleton().createPlane("floor" + std::to_string(i), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, plane_size, plane_size, 10, 10, true, 1, 1000.0f, 1000.0f, Ogre::Vector3::UNIT_Z);
    else
      Ogre::MeshManager::getSingleton().createPlane("floor" + std::to_string(i), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, ground_size, plane_size, 1, 10, true, 1, 10.0f, 1000.0f, Ogre::Vector3::UNIT_Z);
    plane_entities[i] = p_scene_manager->createEntity("plane" + std::to_string(i), "floor" + std::to_string(i));
    plane_entities[i]->setMaterialName("ExternalTerrain");
    plane_entities[i]->setCastShadows(false);
    plane_nodes[i] = p_scene_manager->getRootSceneNode()->createChildSceneNode();
    plane_nodes[i]->attachObject(plane_entities[i]);
    }

  plane_nodes[0]->setPosition(GroundConstants::ORIGIN_X - plane_size / 2, GroundConstants::WATER_LEVEL -0.01f, GroundConstants::ORIGIN_Z);
  plane_nodes[1]->setPosition(GroundConstants::ORIGIN_X + ground_size / 2, GroundConstants::WATER_LEVEL -0.01f, GroundConstants::ORIGIN_Z - plane_size / 2);
  plane_nodes[2]->setPosition(GroundConstants::ORIGIN_X + ground_size + plane_size / 2, GroundConstants::WATER_LEVEL -0.01f, GroundConstants::ORIGIN_Z);
  plane_nodes[3]->setPosition(GroundConstants::ORIGIN_X + ground_size / 2 , GroundConstants::WATER_LEVEL -0.01f, GroundConstants::ORIGIN_Z + plane_size / 2 + ground_size);

  // 2) compute scale for wall element
  const double default_cube_size = 100.0;
  const double wall_scale_x = WallConstants::WALL_DEPTH  / default_cube_size;
  const double wall_scale_y = WallConstants::WALL_HEIGHT / default_cube_size;
  const double wall_scale_z = WallConstants::WALL_LENGTH  / default_cube_size;

  // 3) create wall around ground  
  const size_t wall_object_number = 4;
  std::vector<Ogre::Entity*> wall_entities(wall_object_number);
  std::vector<Ogre::SceneNode*> wall_nodes(wall_object_number);

  const std::string wall_material_name = "WallMaterial";

  // create entities and nodes
  for (size_t i = 0; i < wall_object_number; ++i)
    {
    wall_entities[i] = p_scene_manager->createEntity(Ogre::SceneManager::PrefabType::PT_CUBE);
    wall_entities[i]->setMaterialName(wall_material_name);

    wall_nodes[i] = p_scene_manager->getRootSceneNode()->createChildSceneNode();
    wall_nodes[i]->attachObject(wall_entities[i]);
    }

  // set each node to its position
  const double y_position = 0;

  wall_nodes[0]->setScale(wall_scale_x, wall_scale_y, wall_scale_z);
  wall_nodes[0]->setPosition(GroundConstants::ORIGIN_X - GroundConstants::CELL_SIZE / 4.0, y_position, GroundConstants::ORIGIN_Z + GroundConstants::CELL_COUNT*GroundConstants::CELL_SIZE / 2);

  wall_nodes[1]->setScale(wall_scale_x, wall_scale_y, wall_scale_z);
  wall_nodes[1]->setPosition(GroundConstants::ORIGIN_X + GroundConstants::CELL_COUNT*GroundConstants::CELL_SIZE + GroundConstants::CELL_SIZE / 4.0, y_position, GroundConstants::ORIGIN_Z + (GroundConstants::CELL_COUNT)*GroundConstants::CELL_SIZE / 2);

  wall_nodes[2]->setScale(wall_scale_z, wall_scale_y, wall_scale_x);
  wall_nodes[2]->setPosition(GroundConstants::ORIGIN_X + GroundConstants::CELL_COUNT*GroundConstants::CELL_SIZE / 2, y_position, GroundConstants::ORIGIN_Z - GroundConstants::CELL_SIZE / 4.0);

  wall_nodes[3]->setScale(wall_scale_z, wall_scale_y, wall_scale_x);
  wall_nodes[3]->setPosition(GroundConstants::ORIGIN_X + GroundConstants::CELL_COUNT*GroundConstants::CELL_SIZE / 2, y_position, GroundConstants::ORIGIN_Z + GroundConstants::CELL_COUNT*GroundConstants::CELL_SIZE + GroundConstants::CELL_SIZE / 4.0);

  }
